#!/usr/bin/env python
# -*- coding: utf-8 -*-

from client.contractnote import ContractNote
from client.bcosclient import BcosClient
import os
from eth_utils import to_checksum_address
from client.datatype_parser import DatatypeParser
from client.common.compiler import Compiler
from client.bcoserror import BcosException, BcosError
from client_config import client_config
import sys
import traceback


class FundrasingConfig(object):
    """
    使用Python-sdk来运用Fundraising合约的必要设置
    """
    abi_file = "contracts/Fundraise.abi"
    bin_file = "contracts/Fundraise.bin"
    sol_file = "contracts/Fundraise.sol"
    contractAddress = "0x84139e0d46160aa2dd2541f499049095596891c9"
    contractName = "Fundraise"


class FundrasingInterface(object):
    """
    将合约对应的功能进一步封装，对应于Fundraising合约，提供接口供UI调用
    """

    def __init__(self, config):
        """
        用于调用sdk的预先配置
        :param config: 类FundraisingConfig，包含了abi文件路径，合约地址等等
        """
        self.config = config
        self.data_parser = DatatypeParser()
        self.data_parser.load_abi_file(self.config.abi_file)
        self.contract_abi = self.data_parser.contract_abi
        self.client = BcosClient()
        print(self.client.getinfo)

    def sendTransaction(self, func, args):
        """
        对Python-sdk的交易接口进行封装，用于发送交易上链
        :param func: 对应于合约的方法名，字符串类型
        :param args: 对应合约该方法需要的参数，数组类型，顺序对应
        :return:
        outputResult: 对应方法的返回值，元组形式，其中按顺序存放了相应返回值。
        """
        receipt = self.client.sendRawTransactionGetReceipt(self.config.contractAddress,
                                                           self.contract_abi, func, args)
        # print("receipt:", receipt)
        # 解析receipt里的log
        # print("\n>>parse receipt and transaction:--------------------------------------")
        txhash = receipt['transactionHash']
        # print("transaction hash: ", txhash)
        # logresult = self.data_parser.parse_event_logs(receipt["logs"])
        # i = 0
        # for log in logresult:
        #     if 'eventname' in log:
        #         i = i + 1
        #         print("{}): log name: {} , data: {}".format(i, log['eventname'], log['eventdata']))
        # 获取对应的交易数据，解析出调用方法名和参数
        txresponse = self.client.getTransactionByHash(txhash)
        inputresult = self.data_parser.parse_transaction_input(txresponse['input'])
        # print("transaction input parse:", txhash)
        # print(inputresult)
        # 解析该交易在receipt里输出的output,即交易调用的方法的return值
        outputresult = self.data_parser.parse_receipt_output(inputresult['name'], receipt['output'])
        # print("receipt output :", outputresult)
        return outputresult

    def call(self, func, args=None):
        """
        封装了python-sdk的call函数，可以用于调用合约方法，不上链
        :param func:  调用的合约接口方法名，字符串类型
        :param args:  调用合约接口的参数，数组类型，如不需要参数则为None，默认值为None
        :return: res: 调用相应方法后的返回值， 元组形式，按顺序存放了方法的返回值。
        """
        if args is None:
            res = self.client.call(self.config.contractAddress,
                                   self.contract_abi, func)
        else:
            res = self.client.call(self.config.contractAddress,
                                   self.contract_abi, func, args)
        return res

    def finish(self):
        """
        调用完毕，终止打开的python-sdk客户端
        :return:
        """
        self.client.finish()

    def getAccount(self, name):
        """
        先调用isRegistered验证是否存在用户再get
        感觉加个判断好一点
        :param name: 账户名
        :return:
        name：账户名
        role：账户角色
        balance：账户余额
        """
        if type(name) != str:
            return "type error"
        elif name == "":
            return "invalid username"
        res = self.call("getAccount", [name])
        return res

    def register(self, name, password, role):
        """
        注册账户
        :param password:
        :param name: 账户账号，string类型
        :param role: 账户角色, uint类型
        :return:
        bool 类型  注册结果
        
        """
        if type(name) != str or type(role) != int:
            return False, "type error"
        elif name == "" or (role < 0 or role > 1):
            return False, "value error"
        res = self.sendTransaction("register", [name, password, role])
        print(res)	
        if res[0] == 0:
            return True
        elif res[0] == 1:
            return False

    def login(self, name, password):
        """

        :param name: 账户账号，string
        :param password:账户密码，string
        :return:
        int 类型 0 代表成功 1 代表账号不存在 2 代表密码错误
        """
        if type(name) != str or type(password) != str:
            return False, "type error"
        elif name == "":
            return False, "invalid username"
        res = self.call("login", [name, password])
        print(res)
        if res[0] == 0:
            return 0
        elif res[1] == 1:
            return 1
        elif res[2] == 2:
            return 2

    def isRegistered(self, name):
        """

        :param name: 账户账户
        :return:
        bool 类型 存在与否
        """
        if type(name) != str:
            return "type error"
        elif name == "":
            return "invalid username"
        res = self.call("isRegistered", [name])
        print(res)
        if res[0] == 0:
            return True
        else:
            return False

    def raiseFundraising(self, name, target, description):
        """
        存疑
        :param name: 发起人账户名
        :param target: 目标金额
        :param description: 募捐描述
        :return:
        bool，是否成功
        """
        if type(name) != str:
            return "type error"
        elif name == "":
            return "invalid username"
        res = self.sendTransaction("raiseFundraising", [name, target, description])
        print(res)
        if res[0] == 1:
            return False
        elif res[0] == 0:
            return True

    def auditFundraising(self, name, ID, audit):
        """

        :param name: 账户名
        :param ID: 募捐项目ID
        :param audit: 要修改的状态
        :return:
        code：0成功
        """
        if type(name) != str or type(ID) != int or type(audit) != int:
            return 1, "type error"
        elif name == "":
            return 1, "invalid username"
        res = self.sendTransaction("auditFundraising", [name, ID, audit])
        print(res)
        if res[0] == 0:
            return True
        elif res[0] == 1:
            return False

    def getFundraising(self, ID):
        """
        :param ID:募捐项目ID
        :return:
        target：募捐目标
        owned：已募捐金额
        status：状态
        description：项目描述
        """
        res = self.call("getFundraising", [ID])
        print(res)
        return res
    '''
    def getFundraisings(self):
        """
        有待修改 要不然太反人类了
        :return:
        target：募捐目标
        owned：已募捐金额
        status：状态
        description：项目描述
        """
        res = self.call("getFundraisings")
        print(res)
        return res
    '''

    
    def getFundraisings(self):
        """
        :return:

        target：募捐目标
        owned：已募捐金额
        status：状态

        description：项目描述
        """
        res = self.getFundraisingLength()
        result = []
        for i in range(res):
            temp = self.getFundraising(i + 1)
            result.append(temp)
        print(result)
        return result
    

    
    def getAuditedFundraisings(self):

        """
        :return:
        target：募捐目标
        owned：已募捐金额
        status：状态
        description：项目描述
        """
        res = self.getFundraisingLength()
        result = []
        for i in range(res):
            temp = self.getFundraising(i + 1)
            if temp[2] == 1:
                result.append(temp)
        return result
    '''

    def getAuditedFundraisings(self):
        """
        有待修改 要不然太反人类了
        :return:
        target：募捐目标
        owned：已募捐金额
        status：状态
        description：项目描述
        """
        res = self.call("getAuditedFundraisings")
        print(res)
        return res
    '''
    def getFundraisingLength(self):
        """
        :return:目前项目数量
        """
        res = self.call("getFundraisingLength")
        return res[0]

    def donate(self, name, fundraisingID, amount):
        """
        :param name:捐款人用户名
        :param fundraisingID: 募捐项目ID
        :param amount: 捐款金额
        :return:
        code：0成功，1余额不足，2项目已筹集齐 3输入有误
        """
        if type(name) != str or type(fundraisingID) != int or type(amount) != int:
            return 3
        elif name == "":
            return 3
        res = self.sendTransaction("donate", [name, fundraisingID, amount])
        print(res)
        if res[0] == 1:
            return 1
        elif res[0] == 2:
            return 2
        elif res[0] == 0:
            return 0

    def getDonations(self, name):
        """
        :param name: 账户名
        :return:
        donations[]具体细节不清楚
        """
        res = self.getDonationIDs(name)
        result = []
        for i in res:
            temp = self.getDonation(i)
            result.append(temp)
        print(result)
        return result

    def getDonationIDs(self, name):
        """
        :param name: 账户名
        :return:
        donations[]具体细节不清楚
        """
        res = self.call("getDonationIDs", [name])
        print(res)
        return res[0]
    
    def getDonation(self, ID):
        """
        :param name: 账户名
        :return:
        donations[]具体细节不清楚
        """
        res = self.call("getDonation", [ID])
        print(res)
        return res

if __name__ == "__main__":
    config = FundrasingConfig()
    print("config info:")
    print("config abi: ", config.abi_file)
    print("config bin: ", config.bin_file)
    print("config sol: ", config.sol_file)
    print("config address: ", config.contractAddress)
    intereface = FundrasingInterface(config)
    print("register account: ")
    res = intereface.register("admin", "123456", 1)
    print("register return: ", res)
    print("registered ? ")
    res = intereface.isRegistered("admin")
    print("isRegistered return: ", res)
    print("login: ")
    res = intereface.login("admin", "123456")
    print("login return: ", res)
    print("account get: ")
    res = intereface.getAccount("admin")
    print("account return: ", res)
    print("raise project:")
    res = intereface.raiseFundraising("admin", 1000, "for test")
    print("raise return: ", res)
    print("audit project")
    res = intereface.auditFundraising("admin", 1, 1)
    print("audit return: ", res)
    print("get project")
    res = intereface.getFundraising(1)
    print("project return: ", res)
    print("projects get: ")
    res = intereface.getFundraisings()
    print("projects return: ", res)
    print("project length get: ")
    res = intereface.getFundraisingLength()
    print("project length return: ", res)
    print("donate project:")
    res = intereface.donate("admin", 1, 100)
    print("donate return:", res)
    print("get project")
    res = intereface.getFundraising(1)
    print("project return: ", res)
    print("donate projects:")
    res = intereface.getDonations("admin")
    print("donate return:", res)
    print("finish >>>>>>>>>")
    intereface.finish()
	
	

